#include <variant>
#include <vector>

#include <logger.h>

template<class... Ts>
struct overloaded : Ts... {
    using Ts::operator()...;
};
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

int main()
{
    std::variant<std::monostate, unsigned, float> variant;
    VALUE_LOGGER(std::get_if<unsigned>(&variant)); // 0
    VALUE_LOGGER(std::get_if<float>(&variant)); // 0
    VALUE_LOGGER(variant.index()); // 0
    VALUE_LOGGER(std::holds_alternative<unsigned>(variant)); // false
    VALUE_LOGGER(std::holds_alternative<float>(variant)); // false
    variant = 1u;
    VALUE_LOGGER(std::get<unsigned>(variant)); // 1
    VALUE_LOGGER(std::get_if<unsigned>(&variant)); // 0x7ffdab9880b0
    VALUE_LOGGER(std::get_if<float>(&variant)); // 0
    VALUE_LOGGER(variant.index()); // 1
    VALUE_LOGGER(std::holds_alternative<unsigned>(variant)); // true
    VALUE_LOGGER(std::holds_alternative<float>(variant)); // false
    variant = 2.5f;
    VALUE_LOGGER(std::get<float>(variant)); // 2.5
    VALUE_LOGGER(std::get_if<unsigned>(&variant)); // 0
    VALUE_LOGGER(std::get_if<float>(&variant)); // 0x7ffdab9880b0
    VALUE_LOGGER(variant.index()); // 2
    VALUE_LOGGER(std::holds_alternative<unsigned>(variant)); // false
    VALUE_LOGGER(std::holds_alternative<float>(variant)); // true

    std::vector<std::variant<unsigned, float, std::string>> variants = {1u, 2.5f, "hello"};
    for (const auto &v : variants) {
        std::visit(overloaded {
            [](auto a) { VALUE_LOGGER(a); },
            [](unsigned u) { VALUE_LOGGER(u); },
            [](float f) { VALUE_LOGGER(f); },
        }, v);
    } // u: 1
      // f: 2.5
      // a: hello

    for (const auto &v : variants) {
        std::visit(overloaded {
            [](auto a) { VALUE_LOGGER(a); },
        }, v);
    } // a: 1
      // a: 2.5
      // a: hello

    variants.clear();
    variants.push_back(1u);
    variants.push_back(2.6f);
    variants.push_back("world");
    for (const auto &v : variants) {
        std::visit(overloaded {
            [](auto a) { VALUE_LOGGER(sizeof(a)); },
        }, v);
    } // sizeof(a): 4
      // sizeof(a): 4
      // sizeof(a): 32

    std::vector<float> floats = {2.5f, 3.5f, 4.5f};
    variants.insert(variants.end(), floats.begin(), floats.end());
    for (const auto &v : variants) {
        std::visit(overloaded {
            [](auto a) { VALUE_LOGGER(a); },
            [](unsigned u) { VALUE_LOGGER(u); },
            [](float f) { VALUE_LOGGER(f); },
        }, v);
    } // u: 1
      // f: 2.6
      // a: world
      // f: 2.5
      // f: 3.5
      // f: 4.5
    return 0;
}
